LL_SPI_Init and LL_SPI_DeInit APIs migration

The LL initialization and de-initialization functions previously available in the stm32tnxx_ll_spi.c files within HAL1 are no longer present in HAL2. In HAL2, all LL C files ( stm32tnxx_ll_spi.c) have been removed, leaving only the LL header files ( stm32tnxx_ll_spi.h) that contain static inline functions.

If users need to initialize or de-initialize SPI using the LL layer, they have two methods:

  • Utilize STM32CubeMX2 Code Generation: Rely on STM32CubeMX2 to generate code with the LL layer for SPI initialization and de-initialization.

  • Replace manually the initialization and de-initialization functionsReplace the LL_SPI_Init and LL_SPI_DeInit functions

    manually with equivalent sequences using the static inline functions provided in the stm32tnxx_ll_spi.h file, tailored to their specific configuration and requirements.

This approach ensures that the initialization and de-initialization sequences are precisely addressing the given use case based on the LL static inline functions provided in the stm32tnxx_ll_spi.h header file. The sequences offer improved footprint optimization compared to the previous LL initialization functions found in stm32tnxx_ll_spi.c.

Related concept:

Method 1: Utilize STM32CubeMX2 Code Generation

LL SPI configuration panel

Create a new project with the STM32CubeMX2, then start the initialization and the main configuration.

Project configuration panel

SPI main features configuration

Configure the SPI main features.

SPI LL layer selection

SPI advanced features configuration

Configure the advanced SPI features if needed.

Example Image

GPIO configuration

Configure GPIO pins

Example Image

DMA configuration

Configure the DMA for data reception as needed.

Example Image

NVIC configuration

Configure the NVIC in case of an interrupt.

Example Image

Generated SPI initialization sequence

The SPI initialization and deinitialization sequences are generated in the mx_spi1_init and mx_spi1_deinit functions in mx_spi1.c file under $YOUR_PROJECT_NAME$/$YOUR_PROJECT_NAME$_SW/generated/STM32Cube_CodeGen.

STM32CubeMX2 Generated : SPI initialization sequence

HAL1

HAL2

Initialization and configuration sequence

static void MX_SPI1_Init(void)
{

  LL_SPI_InitTypeDef SPI_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_SYSCLK);

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

  /**SPI1 GPIO Configuration
  PA5   ------> SPI1_SCK
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_6|LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* SPI1 interrupt Init */
  NVIC_SetPriority(SPI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(SPI1_IRQn);

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV256;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 0x7;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_EnableNSSPulseMgt(SPI1);
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

static void MX_GPDMA1_Init(void)
{
LL_DMA_InitTypeDef DMA_InitStruct = {0};

/* Peripheral clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);

DMA_InitStruct.SrcAddress = 0x00000000U;
DMA_InitStruct.DestAddress = 0x00000000U;
DMA_InitStruct.Direction = LL_DMA_DIRECTION_MEMORY_TO_MEMORY;
DMA_InitStruct.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST;
DMA_InitStruct.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD;
DMA_InitStruct.SrcBurstLength = 1;
DMA_InitStruct.DestBurstLength = 1;
DMA_InitStruct.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
DMA_InitStruct.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
DMA_InitStruct.SrcIncMode = LL_DMA_SRC_FIXED;
DMA_InitStruct.DestIncMode = LL_DMA_DEST_FIXED;
DMA_InitStruct.Priority = LL_DMA_LOW_PRIORITY_LOW_WEIGHT;
DMA_InitStruct.BlkDataLength = 0x00000000U;
DMA_InitStruct.TriggerMode = LL_DMA_TRIGM_BLK_TRANSFER;
DMA_InitStruct.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED;
DMA_InitStruct.TriggerSelection = 0x00000000U;
DMA_InitStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
DMA_InitStruct.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0;
DMA_InitStruct.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT0;
DMA_InitStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT1;
DMA_InitStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION;
DMA_InitStruct.LinkedListBaseAddr = 0x00000000U;
DMA_InitStruct.LinkedListAddrOffset = 0x00000000U;

LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_0, &DMA_InitStruct);
}

void SPI1_IRQHandler(void)
{
/* USER CODE */
}
SPI_TypeDef *mx_spi1_init(void)
{
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

  LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_PCLK2);

  uint32_t cfg1_config = LL_SPI_DATA_WIDTH_8_BIT | LL_SPI_BAUD_RATE_PRESCALER_2;
  uint32_t cfg2_config = LL_SPI_MODE_MASTER | LL_SPI_FULL_DUPLEX | LL_SPI_CLOCK_POLARITY_LOW
                       | LL_SPI_CLOCK_PHASE_1_EDGE | LL_SPI_MSB_FIRST | LL_SPI_NSS_SOFT;

  LL_SPI_SetConfig(SPI1, cfg1_config, cfg2_config);

  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);

  LL_SPI_SetInterDataIdleness(SPI1, LL_SPI_MIDI_DELAY_0_CYCLE);

  LL_SPI_SetReadyPinPolarity(SPI1, LL_SPI_READY_PIN_POLARITY_HIGH);
  LL_SPI_EnableReadyPin(SPI1);

  LL_SPI_SetFIFOThreshold(SPI1, LL_SPI_FIFO_THRESHOLD_1_DATA);

  LL_SPI_EnableMasterRxAutoSuspend(SPI1);

  LL_SPI_EnableGPIOControl(SPI1);

  LL_SPI_EnableMosiMisoSwap(SPI1);

  LL_SPI_EnableIOLock(SPI1);

  LL_SPI_EnableDelayReadDataSampling(SPI1);

  /* GPIO Clocks activation */
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

  /* Configure IO output speed (Low, Medium, High or Very-High) */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_6, LL_GPIO_SPEED_FREQ_HIGH);

  /* Configure IO output type (Push-Pull or Open-Drain) */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5 | LL_GPIO_PIN_6, LL_GPIO_OUTPUT_PUSHPULL);

  /* Activate the Pull-up, Pull-down resistor, or No pull for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_5, LL_GPIO_PULL_NO);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_6, LL_GPIO_PULL_NO);

  /* Configure the Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_5, LL_GPIO_AF_5);
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_6, LL_GPIO_AF_5);

  /* Configure IO direction mode (Input, Output, Alternate or Analog) */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_6, LL_GPIO_MODE_ALTERNATE);

  /* Configure IO output speed (Low, Medium, High or Very-High) */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_4, LL_GPIO_SPEED_FREQ_HIGH);

  /* Configure IO output type (Push-Pull or Open-Drain) */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_4, LL_GPIO_OUTPUT_PUSHPULL);

  /* Activate the Pull-up, Pull-down resistor, or No pull for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_4, LL_GPIO_PULL_NO);

  /* Configure the Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_4, LL_GPIO_AF_4);

  /* Configure IO direction mode (Input, Output, Alternate or Analog) */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_4, LL_GPIO_MODE_ALTERNATE);

  /* Configure IO output speed (Low, Medium, High or Very-High) */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_HIGH);

  /* Configure IO output type (Push-Pull or Open-Drain) */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_PUSHPULL);

  /* Activate the Pull-up, Pull-down resistor, or No pull for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);

  /* Configure the Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_0, LL_GPIO_AF_6);

  /* Configure IO direction mode (Input, Output, Alternate or Analog) */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_0, LL_GPIO_MODE_ALTERNATE);

return SPI1;
}

Deinitialization sequence

static void MX_SPI1_DeInit(void)
{
  LL_SPI_DeInit(&hSPI1)
}
void mx_spi1_deinit(void)
{
  LL_SPI_Disable(SPI1);

  /* ### GPIO deinitialization of SPI1: SPI1_SCK,SPI1_MISO ########################### */

  /* Configure IO in Analog Mode */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_ANALOG);
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_6, LL_GPIO_MODE_ANALOG);

  /* Configure the default Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_5, LL_GPIO_AF_0);
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_6, LL_GPIO_AF_0);

  /* Configure the default value for IO Speed */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_LOW);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_6, LL_GPIO_SPEED_FREQ_LOW);

  /* Configure the default value IO Output Type */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5 | LL_GPIO_PIN_6, LL_GPIO_OUTPUT_PUSHPULL);

  /* Deactivate the Pull-up and Pull-down resistor for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_5, LL_GPIO_PULL_NO);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_6, LL_GPIO_PULL_NO);

  /* Reset the IO output state */
  LL_GPIO_WriteOutputPin(GPIOA, LL_GPIO_PIN_5 | LL_GPIO_PIN_6, LL_GPIO_PIN_RESET);

  /* ### GPIO deinitialization of SPI1: SPI1_MOSI ########################### */

  /* Configure IO in Analog Mode */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_4, LL_GPIO_MODE_ANALOG);

  /* Configure the default Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_4, LL_GPIO_AF_0);

  /* Configure the default value for IO Speed */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_4, LL_GPIO_SPEED_FREQ_LOW);

  /* Configure the default value IO Output Type */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_4, LL_GPIO_OUTPUT_PUSHPULL);

  /* Deactivate the Pull-up and Pull-down resistor for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_4, LL_GPIO_PULL_NO);

  /* Reset the IO output state */
  LL_GPIO_WriteOutputPin(GPIOA, LL_GPIO_PIN_4, LL_GPIO_PIN_RESET);

  /* ### GPIO deinitialization of SPI1: SPI1_RDY ########################### */

  /* Configure IO in Analog Mode */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_0, LL_GPIO_MODE_ANALOG);

  /* Configure the default Alternate Function in current IO */
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_0, LL_GPIO_AF_0);

  /* Configure the default value for IO Speed */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_LOW);

  /* Configure the default value IO Output Type */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_PUSHPULL);

  /* Deactivate the Pull-up and Pull-down resistor for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);

  /* Reset the IO output state */
  LL_GPIO_WriteOutputPin(GPIOA, LL_GPIO_PIN_0, LL_GPIO_PIN_RESET);

  /* De-initialize the DMA channel */
  LL_DMA_DisableChannel(LPDMA1_CH1);
  LL_DMA_ClearFlag(LPDMA1_CH1, LL_DMA_FLAG_ALL);

  LL_DMA_WRITE_REG(LPDMA1_CH1, CCR, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH1, CTR1, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH1, CTR2, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH1, CBR1, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH1, CLLR, 0U);

  /* Disable the interruption for DMA */
  NVIC_DisableIRQ(LPDMA1_CH1_IRQn);

  /* De-initialize the DMA channel */
  LL_DMA_DisableChannel(LPDMA1_CH0);
  LL_DMA_ClearFlag(LPDMA1_CH0, LL_DMA_FLAG_ALL);

  LL_DMA_WRITE_REG(LPDMA1_CH0, CCR, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH0, CTR1, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH0, CTR2, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH0, CBR1, 0U);
  LL_DMA_WRITE_REG(LPDMA1_CH0, CLLR, 0U);

  /* Disable the interruption for DMA */
  NVIC_DisableIRQ(LPDMA1_CH0_IRQn);
}

Method 2: Replace manually the initialization and de-initialization functions

LL_SPI_Init() API migration

According to the use-case, implement the precise sequence call based on the LL static inline functions provided in the stm32tnxx_ll_spi.h header file.

SPI Mode Comparison between HAL1 and HAL2

HAL1

HAL2

LL_SPI_InitTypeDef SPI_InitStruct;

SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct->Mode              = LL_SPI_MODE_SLAVE;
SPI_InitStruct->DataWidth         = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct->ClockPolarity     = LL_SPI_POLARITY_LOW;
SPI_InitStruct->ClockPhase        = LL_SPI_PHASE_1EDGE;
SPI_InitStruct->NSS               = LL_SPI_NSS_HARD_INPUT;
SPI_InitStruct->BaudRate          = LL_SPI_BAUDRATEPRESCALER_DIV2;
SPI_InitStruct->BitOrder          = LL_SPI_MSB_FIRST;
SPI_InitStruct->CRCCalculation    = LL_SPI_CRCCALCULATION_ENABLE;
SPI_InitStruct->CRCPoly           = 7UL;

LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_PCLK2);

uint32_t cfg1_config = LL_SPI_DATA_WIDTH_8_BIT | LL_SPI_BAUD_RATE_PRESCALER_2;
uint32_t cfg2_config = LL_SPI_MODE_MASTER | LL_SPI_FULL_DUPLEX | LL_SPI_CLOCK_POLARITY_LOW
                       | LL_SPI_CLOCK_PHASE_1_EDGE | LL_SPI_MSB_FIRST | LL_SPI_NSS_SOFT;

LL_SPI_SetConfig(SPI1, cfg1_config, cfg2_config);

LL_SPI_SetFIFOThreshold(SPI1, LL_SPI_FIFO_THRESHOLD_1_DATA);

LL_SPI_DeInit() API migration

Note

This example is based on a specific STM32 series. For other SPI instances and/or series, modify the LL_APBx_GRPx and LL_APBx_GRPx defines as needed according to the target series.

Comparison of HAL1 and HAL2

HAL1

HAL2

Case of SPI1

LL_SPI_DeInit(&SPI1);
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);